package edu.bbu.license.client.android.controller.files;

import java.io.File;
import java.util.LinkedList;

import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import edu.bbu.license.client.android.R;
import edu.bbu.license.client.android.controller.BaseController;
import edu.bbu.license.client.android.gui.files.FilesView;
import edu.bbu.license.client.android.gui.files.dialogs.LocalFilePressDialogView;
import edu.bbu.license.client.android.gui.files.dialogs.NewFolderDialogView;
import edu.bbu.license.client.android.gui.files.dialogs.ServerFilePressDialogView;
import edu.bbu.license.client.android.services.BaseService;
import edu.bbu.license.client.android.services.exceptions.DuplicationException;
import edu.bbu.license.client.android.services.exceptions.FormatException;
import edu.bbu.license.client.android.services.exceptions.IdentificationException;
import edu.bbu.license.client.android.services.exceptions.NetworkException;
import edu.bbu.license.client.android.services.exceptions.UnknownException;
import edu.bbu.license.client.android.services.file.model.BackFile;
import edu.bbu.license.client.android.services.file.model.FileModel;
import edu.bbu.license.client.android.services.file.model.LocalFile;
import edu.bbu.license.client.android.services.file.model.ServerFile;
import edu.bbu.license.client.android.services.user.worker.SimpleAutentificationService;
import edu.bbu.license.client.android.utility.DelayedExecutor;

public class FilesController extends BaseController {
	
	private static final int CHILD_DIRECTORY = 1;
	private static final int PARRENT_DIRECTORY = 2;
	private static final int FILEVERSION_DIRECTORY = 3;
	private static final int RELOADING_DIRECTORY = 4;
	
	private volatile FilesView filesView;
	private volatile NewFolderDialogView newFolderView;
	private volatile LocalFilePressDialogView localFilePressDialogView;
	private volatile ServerFilePressDialogView serverFilePressDialogView;
	private static FilesController controllerInstance = null;

	private int localDirectoryDepth = 0;
	private LocalFile lastAccesedLocalDirectory = null;
	private Object localDirectoryListingLock = new Object();
	
	private int serverDirectoryDepth = 0;
	private int lastServerDirectoryCommand = 0;
	private ServerFile lastAccesedServerDirectory;
	private ServerFile lastAccesedServerFileVersions;
	private Object serverDirectoryListingLock = new Object();
	
	private LocalFile lastLongPressSelectedLocalFile;
	private ServerFile lastLongPressSelectedServerFile;
	
	private FilesController() { }
	
	public static synchronized FilesController getInstance() {
		if(controllerInstance == null) {
			controllerInstance = new FilesController();
		}
		
		return controllerInstance;
	}
	
	public synchronized void atach(FilesView filesView) {
		if(filesView != null) {
			this.filesView = filesView;
			initializeFilesView();
		}
	}
	
	public synchronized void atach(NewFolderDialogView newFolderView) {
		if(newFolderView != null) {
			this.newFolderView = newFolderView;
			initializeNewFolderView();
		}
	}
	
	public synchronized void atach(LocalFilePressDialogView localFilePressDialogView) {
		if(localFilePressDialogView != null) {
			this.localFilePressDialogView = localFilePressDialogView;
			initializeLocalFilePressView();
		}
	}
	
	public synchronized void atach(ServerFilePressDialogView serverFilePressDialogView) {
		if(serverFilePressDialogView != null) {
			this.serverFilePressDialogView = serverFilePressDialogView;
			initializeServerFilePressView();
		}
	}
	
	public void initializeLocalFilePressView() {
		localFilePressDialogView.setUploadButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						if(lastLongPressSelectedLocalFile != null && lastAccesedServerDirectory != null) {	
							localFilePressDialogView.closeDialogView();
							
							try {
								getTransferService().startUpload(lastLongPressSelectedLocalFile, lastAccesedServerDirectory);
								loadServerDirectoryContent("", RELOADING_DIRECTORY);
							} catch (Exception e) { }						
						}
					}
				});
			}
		});
		
		localFilePressDialogView.setDeleteButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						if(lastLongPressSelectedLocalFile != null) {
							if(!localFilePressDialogView.isFileDeleteRequestConfirmed()) {
								localFilePressDialogView.confirmFileDeleteRequest();
							} else {
								try {
									getFileService().deleteLocalFile(lastLongPressSelectedLocalFile);
									localFilePressDialogView.closeDialogView();
									
									loadLocalDirectoryContent("", RELOADING_DIRECTORY);
									refreshCurrentLocalDirectory();
								} catch (Exception e) {
									localFilePressDialogView.closeDialogView();
								}
							}
						}
					}
				});
			}
		});
		
		localFilePressDialogView.setCancelButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				localFilePressDialogView.closeDialogView();				
			}
		});
	}
	
	public void initializeServerFilePressView() {
		serverFilePressDialogView.setDownloadButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						if(lastLongPressSelectedServerFile != null && lastAccesedLocalDirectory != null && localDirectoryDepth != 0) {
							serverFilePressDialogView.closeDialogView();
							
							try {
								getTransferService().startDownload(lastLongPressSelectedServerFile, lastAccesedLocalDirectory);
								loadLocalDirectoryContent("", RELOADING_DIRECTORY);
							} catch (Exception e) { }							
						}
					}
				});				
			}
		});
		
		serverFilePressDialogView.setDeleteButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread( new Runnable() {
					@Override
					public void run() {
						if(lastLongPressSelectedServerFile != null) {
							if(!serverFilePressDialogView.isFileDeleteRequestConfirmed()) {
								serverFilePressDialogView.confirmFileDeleteRequest();
							} else {
								try {
									getFileService().deleteServerFile(lastLongPressSelectedServerFile);
									serverFilePressDialogView.closeDialogView();
									
									loadServerDirectoryContent("", RELOADING_DIRECTORY);
									refreshCurrentServerDirectory();
								} catch (Exception e) {
									serverFilePressDialogView.closeDialogView();
								}
							}
						}
					}
				});
				
			}
		});
		
		serverFilePressDialogView.setCancelButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				serverFilePressDialogView.closeDialogView();				
			}
		});
	}
	
	public void initializeNewFolderView() {
		newFolderView.setCreateButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						try {
							if(filesView.isLocalFilesViewActive()) {
								synchronized (localDirectoryListingLock) {
									if(lastAccesedLocalDirectory != null) {
										String directoryName = newFolderView.getNewFolderName();
										
										if(!directoryName.isEmpty()) {
											String parrentDirectory = lastAccesedLocalDirectory.getAbsolutePath();
											LocalFile newDirectory = new LocalFile(new File(parrentDirectory, directoryName));
											
											getFileService().createLocalDirectory(newDirectory);
											newFolderView.closeDialogView();
											
											loadLocalDirectoryContent("", RELOADING_DIRECTORY);
											refreshCurrentLocalDirectory();
										} else {
											newFolderView.showError(R.string.files_activity_new_directory_dialog_error_name_empty);
										}
									}
								}
							} else {
								synchronized(serverDirectoryListingLock) {
									if(lastServerDirectoryCommand != FILEVERSION_DIRECTORY) {
										if(lastAccesedServerDirectory != null) {
											String directoryName = newFolderView.getNewFolderName();
											
											if(!directoryName.isEmpty()) {
												String parrentDirectory = lastAccesedServerDirectory.getAbsolutePath();
												ServerFile newDirectory = new ServerFile(parrentDirectory, directoryName, ServerFile.DIRECTORY);
												
												getFileService().createServerDiretory(newDirectory);
												newFolderView.closeDialogView();
												
												loadServerDirectoryContent("", RELOADING_DIRECTORY);
												refreshCurrentServerDirectory();
											} else {
												newFolderView.showError(R.string.files_activity_new_directory_dialog_error_name_empty);
											}
										}
									} else {
										newFolderView.showError(R.string.files_activity_new_directory_dialog_error_versions_view);
									}
								}
							}
						} catch (IdentificationException e) {
							newFolderView.showError(R.string.files_activity_new_directory_dialog_error_unknown_user);
						} catch (FormatException e) {
							newFolderView.showError(R.string.files_activity_new_directory_dialog_error_reserved_chars);
						} catch (DuplicationException e) {
							newFolderView.showError(R.string.files_activity_new_directory_dialog_error_already_exists);
						} catch (UnknownException e) {
							newFolderView.showError(R.string.files_activity_new_directory_dialog_error_unknown);
						} catch (NetworkException e) {
							newFolderView.showError(R.string.app_network_error);
						}
					}
				});
			}
		});
	}
	
	public void initializeFilesView() {
		//Init auto sync.
		getTransferService();
		
		filesView.setHeaderLogoutButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				((SimpleAutentificationService) getAutentificationService()).removeCurrentlyLoggedInUser();
				filesView.openGuestView();
				filesView.closeFilesView();
			}
		});
		
		filesView.setHeaderTrafficButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				filesView.openFileTrafficView();				
			}
		});
		
		filesView.setHeaderSettingsButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				filesView.openSettingsView();				
			}
		});
		
		filesView.setLocalSyncDirectorySetButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				if(lastAccesedLocalDirectory != null && localDirectoryDepth != 0) {
					((BaseService) getFileService()).setLocalSyncDirectory(lastAccesedLocalDirectory.getAbsolutePath());
				}
			}
		});
		
		filesView.setBackButtonListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						if(filesView.isLocalFilesViewActive()) {
							loadLocalDirectoryContent("", PARRENT_DIRECTORY);
							refreshCurrentLocalDirectory();
						} else {
							loadServerDirectoryContent("", PARRENT_DIRECTORY);
							refreshCurrentServerDirectory();
						}
					}
				});
			}
		});
		
		filesView.setRefreshButtonListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {

					@Override
					public void run() {
						if (filesView.isLocalFilesViewActive()) {
							loadLocalDirectoryContent("", RELOADING_DIRECTORY);
							refreshCurrentLocalDirectory();
						} else {
							loadServerDirectoryContent("", RELOADING_DIRECTORY);
							refreshCurrentServerDirectory();
						}
					}
				});
			}
		});

		filesView.setNewDirectoryButtonListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				filesView.openNewFolderDialog();
			}
		});
		
		filesView.setSynchronizeButtonListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				executeInNewThread(new Runnable() {
					public void run() {
						getTransferService().startSynchronization();
						loadLocalDirectoryContent("", RELOADING_DIRECTORY);
						refreshCurrentLocalDirectory();
						loadServerDirectoryContent("", RELOADING_DIRECTORY);
						refreshCurrentServerDirectory();
					}
				});
			}
		});
		
		filesView.setLocalFilesItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(final AdapterView<?> parent, final View v, final int position, final long id) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						FileModel fileModel = (FileModel) parent.getItemAtPosition(position);
						
						if(!fileModel.isFile()) {
							if(fileModel.isDirectory()) {
								loadLocalDirectoryContent(fileModel.getName(), CHILD_DIRECTORY);
							} else {
								loadLocalDirectoryContent("", PARRENT_DIRECTORY);
							}
							
							refreshCurrentLocalDirectory();
						}					
					}
				});
			}
		});
		
		filesView.setServerFilesItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(final AdapterView<?> parent, final View v, final int position, final long id) {
				executeInNewThread(new Runnable() {
					
					@Override
					public void run() {
						FileModel fileModel = (FileModel) parent.getItemAtPosition(position);
						
						if(!fileModel.isFile()) {
							if(fileModel.isDirectory()) {
								loadServerDirectoryContent(fileModel.getName(), CHILD_DIRECTORY);
							} else {
								loadServerDirectoryContent("", PARRENT_DIRECTORY);
							}
						} else {
							if(!((ServerFile) fileModel).isFileVersion()) {
								loadServerDirectoryContent(fileModel.getName(), FILEVERSION_DIRECTORY);
							}
						}
						
						refreshCurrentServerDirectory();
					}
				});
			}			
		});
		
		filesView.setLocalFilesItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
				if(localDirectoryDepth != 0 && position != 0) {
					lastLongPressSelectedLocalFile = (LocalFile) parent.getItemAtPosition(position);
					filesView.openLocalFilesPressDialog();
					
					return true;
				}
				
				return false;
			}
		});
		
		filesView.setServerFilesItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
				if(serverDirectoryDepth != 0) {
					if(position != 0) {
						lastLongPressSelectedServerFile = (ServerFile) parent.getItemAtPosition(position);
						filesView.openServerFilesPressDialog();
						return true;
					}
				} else {
					lastLongPressSelectedServerFile = (ServerFile) parent.getItemAtPosition(position);
					filesView.openServerFilesPressDialog();
					return true;
				}
				
				return false;
			}
		});
		
		executeInNewThread(new Runnable() {
			
			@Override
			public void run() {
				loadLocalDirectoryContent("", RELOADING_DIRECTORY);
				refreshCurrentLocalDirectory();
			}
		});
		
		executeInNewThread(new Runnable() {
			
			@Override
			public void run() {
				loadServerDirectoryContent("", RELOADING_DIRECTORY);
				refreshCurrentServerDirectory();
			}
		});
	}
	
	private void loadLocalDirectoryContent(String directoryName, int type) {
		DelayedExecutor delayedExecutor = new DelayedExecutor(new Runnable() {
			
			@Override
			public void run() {
				filesView.showLocalFilesGridProgressBar();
			}
		});
		
		delayedExecutor.start();
		
		synchronized (localDirectoryListingLock) {			
			int localDirectoryDepthSaving = localDirectoryDepth;
			LocalFile lastAccesedLocalDirectorySaving = lastAccesedLocalDirectory;
			LinkedList<FileModel> fileModels = new LinkedList<FileModel>();
			
			if(type == CHILD_DIRECTORY) {
				localDirectoryDepth++;
			} else if(type == PARRENT_DIRECTORY && localDirectoryDepth > 0) {
				localDirectoryDepth--;
			} 
			
			try {
				if(localDirectoryDepth == 0) {
					lastAccesedLocalDirectory = getFileService().getLocalRootDirectory();
				} else {
					fileModels.add(new BackFile());
					
					if(lastAccesedLocalDirectory != null) {
						if(type == CHILD_DIRECTORY) {
							lastAccesedLocalDirectory = lastAccesedLocalDirectory.getSuccessor(directoryName);
						} else if(type == PARRENT_DIRECTORY) {
							lastAccesedLocalDirectory = lastAccesedLocalDirectory.getAncestor();
						}
					}
				}
				
				if(lastAccesedLocalDirectory != null) {
					fileModels.addAll(getFileService().getLocalDirectoryContent(lastAccesedLocalDirectory));
				}
				
				delayedExecutor.dismiss();
				filesView.fillLocalFilesGrid(fileModels);
				filesView.showLocalFilesGrid();
			} catch (IdentificationException e) {
				localDirectoryDepth = localDirectoryDepthSaving;
				lastAccesedLocalDirectory = lastAccesedLocalDirectorySaving;
				
				delayedExecutor.dismiss();
				filesView.showLocalFilesGridErrorText();
				filesView.setLocalFileGridErrorText(R.string.files_activity_content_error_unknown_user);
			}
		}
	}
	
	private void refreshCurrentLocalDirectory() {
		synchronized (localDirectoryListingLock) {
			if(lastAccesedLocalDirectory != null) {
				filesView.setLocalFilesCurrentDir(lastAccesedLocalDirectory.getAbsolutePath());
			} else {
				filesView.setLocalFilesCurrentDir("-");
			}
		}
	}
	
	private void loadServerDirectoryContent(String directoryName, int command) {
		DelayedExecutor delayedExecutor = new DelayedExecutor(new Runnable() {
			
			@Override
			public void run() {
				filesView.showServerFilesGridProgressBar();
			}
		});
		
		delayedExecutor.start();
		
		synchronized (serverDirectoryListingLock) {
			int serverDirectoryDepthSaving = serverDirectoryDepth;
			ServerFile lastAccesedServerDirectorySaving = lastAccesedServerDirectory;
			LinkedList<FileModel> fileModels = new LinkedList<FileModel>();
			
			if(command == CHILD_DIRECTORY || command == FILEVERSION_DIRECTORY) {
				serverDirectoryDepth++;
			} else if(command == PARRENT_DIRECTORY && serverDirectoryDepth > 0) {
				serverDirectoryDepth--;
			}
			
			try {
				if(serverDirectoryDepth == 0) {
					lastAccesedServerDirectory = getFileService().getServerRootDirectory();
				} else {
					fileModels.add(new BackFile());
					
					if(lastAccesedServerDirectory != null) {
						if(command == CHILD_DIRECTORY) {
							lastAccesedServerDirectory = lastAccesedServerDirectory.getSuccessor(directoryName);
						} else if(command == PARRENT_DIRECTORY) {
							if(lastServerDirectoryCommand != FILEVERSION_DIRECTORY) {
								lastAccesedServerDirectory = lastAccesedServerDirectory.getAncestor();
							}
						} else if(command == FILEVERSION_DIRECTORY) {
							ServerFile tempFile = lastAccesedServerDirectory.getSuccessor(directoryName);
							lastAccesedServerFileVersions = new ServerFile(tempFile.getRegularPath(), tempFile.getName(), ServerFile.FILE);
						}  
					}
				}
				
				if(command == FILEVERSION_DIRECTORY || (command == RELOADING_DIRECTORY && lastServerDirectoryCommand == FILEVERSION_DIRECTORY)) {
					if(lastAccesedServerFileVersions != null) {
						fileModels.addAll(getFileService().getServerFileVersionsContent(lastAccesedServerFileVersions));
					}
					
					lastServerDirectoryCommand = FILEVERSION_DIRECTORY;
				} else {
					if(lastAccesedServerDirectory != null) {
						fileModels.addAll(getFileService().getServerDirectoryContent(lastAccesedServerDirectory));
					}
					
					lastServerDirectoryCommand = command;
				}
				
				delayedExecutor.dismiss();
				filesView.fillServerFilesGrid(fileModels);
				filesView.showServerFilesGrid();
			} catch (IdentificationException e) {
				serverDirectoryDepth = serverDirectoryDepthSaving;
				lastAccesedServerDirectory = lastAccesedServerDirectorySaving;
				
				delayedExecutor.dismiss();
				filesView.showServerFilesGridErrorText();
				filesView.setServerFileGridErrorText(R.string.files_activity_content_error_unknown_user);
			} catch (NetworkException e) {
				serverDirectoryDepth = serverDirectoryDepthSaving;
				lastAccesedServerDirectory = lastAccesedServerDirectorySaving;
				
				delayedExecutor.dismiss();
				filesView.showServerFilesGridErrorText();
				filesView.setServerFileGridErrorText(R.string.app_network_error);
			}
		}
	}
	
	private void refreshCurrentServerDirectory() {
		synchronized (serverDirectoryListingLock) {
			if(lastServerDirectoryCommand != FILEVERSION_DIRECTORY) {
				if(lastAccesedServerDirectory != null) {
					filesView.setServerFilesCurrentDir(lastAccesedServerDirectory.getAbsolutePath().replace("\\", "/"));
				} else {
					filesView.setServerFilesCurrentDir("-");
				}
			} else {
				if(lastAccesedServerFileVersions != null) {
					filesView.setServerFilesCurrentDir(lastAccesedServerFileVersions.getAbsolutePath().replace("\\", "/"));
				} else {
					filesView.setServerFilesCurrentDir("-");
				}
			}
		}
	}
}
